<?php
/**
 * Firal CMS
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://firal.org/license
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to firal-dev@googlegroups.com so we can send you a copy immediately.
 *
 * @category   Firal
 * @package    Firal_Plugin
 * @copyright  Copyright (c) 2008 Firal Developers
 * @license    http://firal.org/license     New BSD License
 * @version    $Id: Plugin.php 11 2008-06-30 16:14:44Z pieterkokx $
 */

/**
 * @see Zend_Loader
 */
require_once 'Zend/Loader.php';
/**
 * @see Firal_Plugin_Abstract
 */
require_once 'Firal/Plugin/Abstract.php';

/**
 * Firal plugin manager
 *
 * @category   Firal
 * @package    Firal_Plugin
 * @copyright  Copyright (c) 2008 MaakSite.nl Productions. (http://productions.maaksite.nl/)
 * @license    http://www.opensource.org/licenses/bsd-license.php     New BSD License
 */
class Firal_Plugin
{
    
    /**
     * Registered plugins
     * 
     * @var array
     */
    protected $_plugins = array();
    
    /**
     * Registered events
     * 
     * @var array
     */
    protected $_events = array();
    
    /**
     * The plugin manager instance
     * 
     * @var Firal_Plugin
     */
    protected static $_instance = null;
    
    
    /**
     * Constructor, private for singleton pattern
     * 
     * @return void
     */
    private function __construct()
    {
        
    }
    
    /**
     * Disable the clone handler for singleton pattern
     * 
     * @return void
     */
    private function __clone()
    {
        
    }
    
    /**
     * Get the instance of this class
     * 
     * @return Firal_Plugin
     */
    public static function getInstance()
    {
        if (null === self::$_instance) {
            self::$_instance = new self();
        }
        
        return self::$_instance;
    }
    
    /**
     * Check if a plugin is registered
     * 
     * @param string $name
     * 
     * @return bool
     */
    public function isRegistered($name)
    {
        return array_key_exists($name, $this->_plugins);
    }
    
    /**
     * Register a new plugin
     * 
     * @param Firal_Plugin_Abstract
     * 
     * @return void
     */
    public function registerPlugin(Firal_Plugin_Abstract $plugin)
    {
        if ($this->isRegistered($plugin->getName())) {
            // TODO: throw exception
        }
        
        $this->_plugins[$plugin->getName()] = $plugin;
        
        $plugin->init();
    }
    
    /**
     * Register a new event
     * 
     * @param string $event
     * @param string $pluginName
     * 
     * @return void
     */
    public function registerEvent($event, $pluginName, $method)
    {
        if (!array_key_exists($event, $this->_events)) {
            $this->_events[$event] = array();
        }
        if (!in_array($pluginName, $this->_events[$event])) {
            if (array_key_exists($pluginName, $this->_plugins)
            && is_callable(array($this->_plugins[$pluginName], $method))) {
                $this->_events[$event][] = array(
                    'plugin' => $pluginName,
                    'method' => $method
                );
            }
        }
    }
    
    /**
     * Trigger an event
     * 
     * @param string $event
     * @param array $arguments
     * 
     * @return mixed
     */
    public function triggerEvent($event, $arguments)
    {
        if (array_key_exists($event, $this->_events)) {
            foreach ($this->_events[$event] as $plugin) {
                $callback = array($this->_plugins[$plugin['plugin']], $plugin['method']);
                
                $arguments = call_user_func_array($callback, $arguments);
            }
        }
        
        return $arguments;
    }
    
    /**
     * Static wrapper for event trigger
     * 
     * @param string $event
     * 
     * @return void
     */
    public static function trigger($event, $arguments)
    {
        return self::getInstance()->triggerEvent($event, $arguments);
    }
}